#ifndef KMCLUSTER_H
#define KMCLUSTER_H

#include <QString>
#include <QDebug>
#include <iostream>
#include <fstream>
#include "KMlocal.h"
#include <cv.h>
#include <cxcore.h>
#include <DbgNew.h>
class KMCluster
{
public:
    KMCluster(CvMat* src, QString &file)
    {
        if(src->rows > 0)
        {
            this->src = src;
            feat = src->cols;
            coH = src->rows;
            coW = src->cols;
            construct(file);
        }
    }

private:
    void construct(QString &file)
    {
        // 'stages' is the max number of stages
        int stages = 500;
        // 'k' is the number of centers
        int k = 4;
        // Number of dimension is number of texture features times
        // number of angle
        int dim = feat;
        // 'maxPts' is the number of points to be clustered
        int maxPts = coH;

        KMterm term(100.0, 0.0, 0.0, 0.0, 0.10, 0.10, 3, 0.50, 10, 0.95);
        term.setAbsMaxTotStage(stages);
        KMdata dataPts(dim, maxPts);

        try
        {
            //QString file = "./output/kmeans.txt";
            ofstream fout(file.toStdString().c_str());

            for(int i=0; i<coH; i++)
            {
                fillPts_Light(i, dataPts[i]);
            }
            // Build filtering structure
            dataPts.buildKcTree();
            // Allocate centers
            KMfilterCenters ctrs(k, dataPts);
            // Hybrid heuristic
            KMlocalHybrid kmHybrid(ctrs, term);
            ctrs = kmHybrid.execute();
            printSummary(kmHybrid, dataPts, ctrs, fout);
            fout.close();
        }
        catch(exception& e)
        {
            qDebug() << e.what();
        }
    }

    void fillPts_Light(int row, KMpoint &p)
    {
        for(int i=0; i<feat; i++)
        {
            p[i] = (double) cvmGet(src, row, i);
        }
    }

    void printSummary(const KMlocal &alg, const KMdata &dataPts, KMfilterCenters &ctrs, ofstream &fout)
    {

        fout << "Number of stages: " << alg.getTotalStages() << "\n";
        fout << "Average distortion: " <<
                     ctrs.getDist(false)/double(ctrs.getNPts()) << "\n";
        // print final center points
        fout << "(Final Center Points: ";
        ctrs.print();
        fout << ")\n";
        // get/print final cluster assignments
        KMctrIdxArray closeCtr = new KMctrIdx[dataPts.getNPts()];
        double* sqDist = new double[dataPts.getNPts()];
        ctrs.getAssignments(closeCtr, sqDist);

        fout	<< "Cluster assignments: \n"
                    << "Number of points" << "\t" << coH<<"\n"
                    << "    Index    Center    Squared Dist\n"
                    << "    -------  --------  ------------\n";

        for (int i = 0; i < dataPts.getNPts(); i++)
        {

            fout    << setw(9) << i
                    << "   " << setw(7) << closeCtr[i]
                    << "   " << setw(10) << sqDist[i]
                    << "\n";
        }

        delete [] sqDist;
    }
    CvMat *src;
    int feat;
    int coH, coW;

};

#endif // KMCLUSTER_H
